
	package com.xcj.common.db;																																																																																																																																																																																																																																																														

	import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.EmptyStackException;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

	/**																																																																																																																																																																																																																																																														
	 * 数据库连接池																																																																																																																																																																																																																																																														
	 * 																																																																																																																																																																																																																																																														
	 * @author  																																																																																																																																																																																																																																																														
	 * 																																																																																																																																																																																																																																																														
	 */																																																																																																																																																																																																																																																														

	public class ConnectPool extends Thread {																																																																																																																																																																																																																																																														

		final private static Log log = LogFactory.getLog(ConnectPool.class);																																																																																																																																																																																																																																																													

		/* 连接池，存放已创建但未使用的连接 */																																																																																																																																																																																																																																																													
		private Stack<Connection> pool = new Stack<Connection>();																																																																																																																																																																																																																																																													

		/* 被返回的数据库连�?,将由线程�?测并返回到池�? */																																																																																																																																																																																																																																																													
		private Stack<Connection> returnedPool = new Stack<Connection>();																																																																																																																																																																																																																																																													

		/* 已被取走、正在使用的连接 */																																																																																																																																																																																																																																																													
		private Map<Connection, UsingConnection> using = new HashMap<Connection, UsingConnection>();																																																																																																																																																																																																																																																													

		/* 空闲连接 */																																																																																																																																																																																																																																																													
		private Map<Connection, Long> freePool = new HashMap<Connection, Long>();																																																																																																																																																																																																																																																													

		/* 已经创建连接池计�? */																																																																																																																																																																																																																																																													
		private int created = 0;																																																																																																																																																																																																																																																													

		/* JDBC Driver�? */																																																																																																																																																																																																																																																													
		String drivers = null;																																																																																																																																																																																																																																																													

		/* 数据库连接字符串 */																																																																																																																																																																																																																																																													
		String url = null;																																																																																																																																																																																																																																																													

		/* 数据库连接用户名 */																																																																																																																																																																																																																																																													
		String user = null;																																																																																																																																																																																																																																																													

		/* 数据库连接密�? */																																																																																																																																																																																																																																																													
		//String password = null;																																																																																																																																																																																																																																																													

		/* 连接池最大数 */																																																																																																																																																																																																																																																													
		int max = 5000;																																																																																																																																																																																																																																																													

		/* JNDI数据�? */																																																																																																																																																																																																																																																													
		//String jndi_name = null;																																																																																																																																																																																																																																																													

		/* 连接池最小数 */																																																																																																																																																																																																																																																													
		int min = 10;																																																																																																																																																																																																																																																													

		/* 空闲连接等待释放的时�?(毫秒) */																																																																																																																																																																																																																																																													
		int idleTime = 180000;																																																																																																																																																																																																																																																													

		/* 连接�?始标�? */																																																																																																																																																																																																																																																													
		boolean startFlg = false;																																																																																																																																																																																																																																																													

		/* 是否�?要停止线�? */																																																																																																																																																																																																																																																													
		boolean stopThread = false;																																																																																																																																																																																																																																																													

		/* 测试连接SQL语句 */																																																																																																																																																																																																																																																													
		String validationQuery = null;																																																																																																																																																																																																																																																													

		/* 各种同步锁对象，据说byte[]对象创建时间�?短，占资料最�? */																																																																																																																																																																																																																																																													
		private byte[] createdLock = new byte[0];																																																																																																																																																																																																																																																													
		private byte[] usingLock = new byte[0];																																																																																																																																																																																																																																																													
		private byte[] poolLock = new byte[0];																																																																																																																																																																																																																																																													
		private byte[] returnedPoolLock = new byte[0];	
		
		private static String driverName;
		private static String dbURL;
		private static String username;
		private static String password;
		

		/* 单实�? */																																																																																																																																																																																																																																																													
		private static ConnectPool instance = new ConnectPool();																																																																																																																																																																																																																																																													

		/**																																																																																																																																																																																																																																																													
		 * 私有的构造方法，防止从外部直接实例化																																																																																																																																																																																																																																																													
		 * 																																																																																																																																																																																																																																																													
		 */																																																																																																																																																																																																																																																													
		private ConnectPool() {																																																																																																																																																																																																																																																													
			/* 初始化数据库连接参数 */																																																																																																																																																																																																																																																												
			init();																																																																																																																																																																																																																																																												

			/* 启动服务线程 */																																																																																																																																																																																																																																																												
			start();																																																																																																																																																																																																																																																												
		}																																																																																																																																																																																																																																																													

		/**																																																																																																																																																																																																																																																													
		 * 从外部取得本类实例的唯一方法																																																																																																																																																																																																																																																													
		 * 																																																																																																																																																																																																																																																													
		 * @return ConnectPool																																																																																																																																																																																																																																																													
		 */																																																																																																																																																																																																																																																													
		public static ConnectPool getInstance() {																																																																																																																																																																																																																																																													
			return instance;																																																																																																																																																																																																																																																												
		}																																																																																																																																																																																																																																																													

		/**																																																																																																																																																																																																																																																													
		 * 从连接池中取得一个数据库连接 如果池中已没有连接，则新创建�?个连�? 被使用的连接放到using对象�?																																																																																																																																																																																																																																																													
		 * 																																																																																																																																																																																																																																																													
		 * @param caller																																																																																																																																																																																																																																																													
		 * @return																																																																																																																																																																																																																																																													
		 */																																																																																																																																																																																																																																																													
		public Connection getConnection(String poolname, String caller) {																																																																																																																																																																																																																																																													
			if (null == caller || caller.length() == 0) {																																																																																																																																																																																																																																																												
				StackTraceElement[] callerStackTrace = new Throwable().getStackTrace();																																																																																																																																																																																																																																																											
				caller = callerStackTrace[1].toString();																																																																																																																																																																																																																																																											
			}																																																																																																																																																																																																																																																												
			Connection conn = null;																																																																																																																																																																																																																																																												
			try {																																																																																																																																																																																																																																																												
				synchronized (poolLock) {																																																																																																																																																																																																																																																											
					conn = (Connection) pool.pop();																																																																																																																																																																																																																																																										
				}																																																																																																																																																																																																																																																											
			} catch (EmptyStackException e) {																																																																																																																																																																																																																																																												
				conn = newConnection();																																																																																																																																																																																																																																																											
			}																																																																																																																																																																																																																																																												

			if (null != conn) {																																																																																																																																																																																																																																																												
				synchronized (usingLock) {																																																																																																																																																																																																																																																											
					using.put(conn, new UsingConnection(conn, caller));																																																																																																																																																																																																																																																										
				}																																																																																																																																																																																																																																																											
			}																																																																																																																																																																																																																																																												
			return conn;																																																																																																																																																																																																																																																												
		}																																																																																																																																																																																																																																																													

		/**																																																																																																																																																																																																																																																													
		 * 创建�?个新的数据库连接																																																																																																																																																																																																																																																													
		 * 																																																																																																																																																																																																																																																													
		 * @return																																																																																																																																																																																																																																																													
		 */																																																																																																																																																																																																																																																													
		private Connection newConnection() {																																																																																																																																																																																																																																																													
			Connection conn = null;																																																																																																																																																																																																																																																												
			try {																																																																																																																																																																																																																																																												
				if (created < max) {																																																																																																																																																																																																																																																											
						Class.forName(driverName);																																																																																																																																																																																																																																																									
						conn = DriverManager.getConnection(dbURL, username, password);																																																																																																																																																																																																																																																									
						if (null != conn) {																																																																																																																																																																																																																																																									
							synchronized (createdLock) {																																																																																																																																																																																																																																																								
								created++;																																																																																																																																																																																																																																																							
								startFlg = true;																																																																																																																																																																																																																																																							
							}																																																																																																																																																																																																																																																								
						}																																																																																																																																																																																																																																																									
				}																																																																																																																																																																																																																																																											
			} catch (Exception e) {																																																																																																																																																																																																																																																												
				if (log.isErrorEnabled()) {																																																																																																																																																																																																																																																											
					log.error("Can't get connection! ", e);																																																																																																																																																																																																																																																										
				}																																																																																																																																																																																																																																																											
			}																																																																																																																																																																																																																																																												
			return conn;																																																																																																																																																																																																																																																												
		}																																																																																																																																																																																																																																																													

		/**																																																																																																																																																																																																																																																													
		 * 返回�?个数据库连接到池中，再由线程返回连接�?																																																																																																																																																																																																																																																													
		 * 																																																																																																																																																																																																																																																													
		 * @param conn																																																																																																																																																																																																																																																													
		 */																																																																																																																																																																																																																																																													
		public void freeConnection(Connection conn) {																																																																																																																																																																																																																																																													
			freeConnection(null, conn);																																																																																																																																																																																																																																																												
		}																																																																																																																																																																																																																																																													

		public void freeConnection(String poolName, Connection conn) {																																																																																																																																																																																																																																																													
			if (null != conn) {																																																																																																																																																																																																																																																												
				synchronized (returnedPoolLock) {																																																																																																																																																																																																																																																											
					returnedPool.push(conn);																																																																																																																																																																																																																																																										
				}																																																																																																																																																																																																																																																											
			}																																																																																																																																																																																																																																																												
		}																																																																																																																																																																																																																																																													

		/**																																																																																																																																																																																																																																																													
		 * 初始化数据链接参数																																																																																																																																																																																																																																																												
		 * 																																																																																																																																																																																																																																																													
		 */																																																																																																																																																																																																																																																													
		private void init() {																																																																																																																																																																																																																																																													
			driverName = Config.getConfig("jdbc.driverClassName");
			dbURL = Config.getConfig("jdbc.url");
			username = Config.getConfig("jdbc.username");
			password = Config.getConfig("jdbc.password");
			max = Integer.parseInt(Config.getConfig("c3p0.maxPoolSize").trim());																																																																																																																																																																																																																																																												
			min = Integer.parseInt(Config.getConfig("c3p0.minPoolSize").trim());																																																																																																																																																																																																																																																												
			validationQuery = Config.getConfig("jdbc.preferredTestQuery");																																																																																																																																																																																																																																																												
			idleTime = Integer.parseInt(Config.getConfig("c3p0.maxIdleTime").trim());																																																																																																																																																																																																																																																												
		}																																																																																																																																																																																																																																																													

		/**																																																																																																																																																																																																																																																													
		 * 连接服务线程，主要作用： 记录已取走的连接 测试返回的连接是否可�?																																																																																																																																																																																																																																																													
		 */																																																																																																																																																																																																																																																													
		public void run() {																																																																																																																																																																																																																																																													
			Connection conn = null;																																																																																																																																																																																																																																																												
			UsingConnection uc = null;																																																																																																																																																																																																																																																												
			while (true && !stopThread) {																																																																																																																																																																																																																																																												
				if (startFlg && created == 0 && pool.size() == 0 && returnedPool.size() == 0 && using.size() == 0) {																																																																																																																																																																																																																																																											
					stopThread = true;																																																																																																																																																																																																																																																										
				} else {																																																																																																																																																																																																																																																											
					/*																																																																																																																																																																																																																																																										
					 * 处理被返回的数据库连�? 判断连接是否由本池创建并发出的，如果不是则直接关�?																																																																																																																																																																																																																																																										
					 * 如果是则测试连接是否有效，无效从池中删除，有效则返回池中																																																																																																																																																																																																																																																										
					 */																																																																																																																																																																																																																																																										
					while (!returnedPool.empty()) {																																																																																																																																																																																																																																																										
						synchronized (returnedPoolLock) {																																																																																																																																																																																																																																																									
							conn = (Connection) returnedPool.pop();																																																																																																																																																																																																																																																								
						}																																																																																																																																																																																																																																																									
						synchronized (usingLock) {																																																																																																																																																																																																																																																									
							uc = (UsingConnection) using.get(conn);																																																																																																																																																																																																																																																								
						}																																																																																																																																																																																																																																																									
						if (null == uc) {																																																																																																																																																																																																																																																									
							try {																																																																																																																																																																																																																																																								
								conn.close();																																																																																																																																																																																																																																																							
							} catch (Exception e) {																																																																																																																																																																																																																																																								
							}																																																																																																																																																																																																																																																								
						}																																																																																																																																																																																																																																																									
						synchronized (usingLock) {																																																																																																																																																																																																																																																									
							using.remove(conn);																																																																																																																																																																																																																																																								
						}																																																																																																																																																																																																																																																									

						if (testOK(conn)) {																																																																																																																																																																																																																																																									
							synchronized (poolLock) {																																																																																																																																																																																																																																																								
								pool.add(conn);																																																																																																																																																																																																																																																							
								freePool.put(conn, System.currentTimeMillis());																																																																																																																																																																																																																																																							
							}																																																																																																																																																																																																																																																								
						} else {																																																																																																																																																																																																																																																									
							if (created > min) {																																																																																																																																																																																																																																																								
								try {																																																																																																																																																																																																																																																							
									conn.close();																																																																																																																																																																																																																																																						
								} catch (Exception e) {																																																																																																																																																																																																																																																							
									if (log.isErrorEnabled()) {																																																																																																																																																																																																																																																						
										log.error("Connection closed failed! ", e);																																																																																																																																																																																																																																																					
									}																																																																																																																																																																																																																																																						
								}																																																																																																																																																																																																																																																							
								synchronized (createdLock) {																																																																																																																																																																																																																																																							
									created--;																																																																																																																																																																																																																																																						
								}																																																																																																																																																																																																																																																							
							}																																																																																																																																																																																																																																																								
						}																																																																																																																																																																																																																																																									
					}																																																																																																																																																																																																																																																										
					// 空闲连接超过�?大空闲时间释放此连接																																																																																																																																																																																																																																																										
					if (!pool.empty()) {																																																																																																																																																																																																																																																										
						Object[] connArray = pool.toArray();																																																																																																																																																																																																																																																									
						for (int i = 0; i < connArray.length; i++) {																																																																																																																																																																																																																																																									
							if ((System.currentTimeMillis() - freePool.get(connArray[i])) > idleTime) {																																																																																																																																																																																																																																																								
								if (created > min) {																																																																																																																																																																																																																																																							
									try {																																																																																																																																																																																																																																																						
										((Connection) connArray[i]).close();																																																																																																																																																																																																																																																					
									} catch (Exception e) {																																																																																																																																																																																																																																																						
										if (log.isErrorEnabled()) {																																																																																																																																																																																																																																																					
											log.error("Connection closed failed! ", e);																																																																																																																																																																																																																																																				
										}																																																																																																																																																																																																																																																					
									}																																																																																																																																																																																																																																																						
									synchronized (createdLock) {																																																																																																																																																																																																																																																						
										created--;																																																																																																																																																																																																																																																					
									}																																																																																																																																																																																																																																																						
									synchronized (poolLock) {																																																																																																																																																																																																																																																						
										pool.remove((Connection) connArray[i]);																																																																																																																																																																																																																																																					
									}																																																																																																																																																																																																																																																						
								}																																																																																																																																																																																																																																																							
							}																																																																																																																																																																																																																																																								
						}																																																																																																																																																																																																																																																									
					}																																																																																																																																																																																																																																																										
				}																																																																																																																																																																																																																																																											
				conn = null;																																																																																																																																																																																																																																																											
				uc = null;																																																																																																																																																																																																																																																											
				/* 避免循环太快 */																																																																																																																																																																																																																																																											
				try {																																																																																																																																																																																																																																																											
					Thread.sleep(50);																																																																																																																																																																																																																																																										
				} catch (InterruptedException ie) {																																																																																																																																																																																																																																																											
				}																																																																																																																																																																																																																																																											
			}																																																																																																																																																																																																																																																												
			stopThread = false;																																																																																																																																																																																																																																																												
		}																																																																																																																																																																																																																																																													

		/**																																																																																																																																																																																																																																																													
		 * 测试连接是否正常																																																																																																																																																																																																																																																													
		 * 																																																																																																																																																																																																																																																													
		 * @param conn																																																																																																																																																																																																																																																													
		 * @return																																																																																																																																																																																																																																																													
		 */																																																																																																																																																																																																																																																													
		public boolean testOK(Connection conn) {																																																																																																																																																																																																																																																													
			boolean result = false;																																																																																																																																																																																																																																																												
			PreparedStatement pstmt = null;																																																																																																																																																																																																																																																												
			ResultSet rs = null;																																																																																																																																																																																																																																																												
			try {																																																																																																																																																																																																																																																												
				pstmt = conn.prepareStatement(validationQuery);																																																																																																																																																																																																																																																											
				rs = pstmt.executeQuery();																																																																																																																																																																																																																																																											
				result = true;																																																																																																																																																																																																																																																											
			} catch (Exception e) {																																																																																																																																																																																																																																																												
				if (log.isErrorEnabled()) {																																																																																																																																																																																																																																																											
					log.error("Test connection failed! ", e);																																																																																																																																																																																																																																																										
				}																																																																																																																																																																																																																																																											
			} finally {																																																																																																																																																																																																																																																												
				if (null != rs) {																																																																																																																																																																																																																																																											
					try {																																																																																																																																																																																																																																																										
						rs.close();																																																																																																																																																																																																																																																									
					} catch (Exception e) {																																																																																																																																																																																																																																																										
					}																																																																																																																																																																																																																																																										
				}																																																																																																																																																																																																																																																											
				if (null != pstmt) {																																																																																																																																																																																																																																																											
					try {																																																																																																																																																																																																																																																										
						pstmt.close();																																																																																																																																																																																																																																																									
					} catch (Exception e) {																																																																																																																																																																																																																																																										
					}																																																																																																																																																																																																																																																										
				}																																																																																																																																																																																																																																																											
			}																																																																																																																																																																																																																																																												
			return result;																																																																																																																																																																																																																																																												
		}																																																																																																																																																																																																																																																													

		/**																																																																																																																																																																																																																																																													
		 * 释放�?有连�?,创建新池																																																																																																																																																																																																																																																													
		 */																																																																																																																																																																																																																																																													
		public void release() {																																																																																																																																																																																																																																																													
			/* 要求停止线程 */																																																																																																																																																																																																																																																												
			stopThread = true;																																																																																																																																																																																																																																																												

			/* 停等待线程结�?,线程结束时会把stopThread置为false */																																																																																																																																																																																																																																																												
			int timeout = 0;																																																																																																																																																																																																																																																												
			while (stopThread) {																																																																																																																																																																																																																																																												
				if (++timeout > 600) {																																																																																																																																																																																																																																																											
					break;																																																																																																																																																																																																																																																										
				}																																																																																																																																																																																																																																																											
				try {																																																																																																																																																																																																																																																											
					Thread.sleep(500);																																																																																																																																																																																																																																																										
				} catch (InterruptedException ie) {																																																																																																																																																																																																																																																											
				}																																																																																																																																																																																																																																																											
			}																																																																																																																																																																																																																																																												

			/* 创建新连接池实例 */																																																																																																																																																																																																																																																												
			instance = new ConnectPool();																																																																																																																																																																																																																																																												

			/* 释放�?有连接，除了Using，Using是正在使用的且会在新的池里被释放 */																																																																																																																																																																																																																																																												
			synchronized (poolLock) {																																																																																																																																																																																																																																																												
				while (!pool.isEmpty()) {																																																																																																																																																																																																																																																											
					try {																																																																																																																																																																																																																																																										
						Connection conn = (Connection) pool.pop();																																																																																																																																																																																																																																																									
						conn.close();																																																																																																																																																																																																																																																									
						created--;																																																																																																																																																																																																																																																									
					} catch (Exception e) {																																																																																																																																																																																																																																																										
					}																																																																																																																																																																																																																																																										
				}																																																																																																																																																																																																																																																											
			}																																																																																																																																																																																																																																																												

			synchronized (returnedPoolLock) {																																																																																																																																																																																																																																																												
				while (!returnedPool.isEmpty()) {																																																																																																																																																																																																																																																											
					try {																																																																																																																																																																																																																																																										
						Connection conn = (Connection) returnedPool.pop();																																																																																																																																																																																																																																																									
						conn.close();																																																																																																																																																																																																																																																									
						created--;																																																																																																																																																																																																																																																									
					} catch (Exception e) {																																																																																																																																																																																																																																																										
					}																																																																																																																																																																																																																																																										
				}																																																																																																																																																																																																																																																											
			}																																																																																																																																																																																																																																																												
		}																																																																																																																																																																																																																																																													
	}																																																																																																																																																																																																																																																														
